package com.matt.service.impl;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.matt.commons.dto.sso.AreaDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.domain.LiveRoom;
import com.matt.domain.VideoCassetteRecorder;
import com.matt.foundation.constant.LiveRoomConstant;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.utils.YinShiUtil;
import com.matt.repository.LiveRoomRepository;
import com.matt.repository.VideoCassetteRecorderRepository;
import com.matt.service.LiveRoomService;
import com.matt.service.VideoCassetteRecorderService;
import com.matt.service.remoteCall.SsoCallService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.matt.foundation.model.ErrorCode.SIGN_ERROR;

/**
 * *******************************
 * Created by Ron.
 * form com.matt
 * on 2017/12/8
 * *******************************
 */
@Service
@Slf4j
public class VideoCassetteRecorderServiceImpl implements VideoCassetteRecorderService {

    @Autowired
    private VideoCassetteRecorderRepository videoCassetteRecorderRepository;

    @Autowired
    private YinShiUtil yinShiUtil;

    @Autowired
    private SsoCallService ssoCallService;

    @Autowired
    private LiveRoomRepository liveRoomRepository;

    @Autowired
    private LiveRoomService liveRoomService;


    @Value("${spring.profiles.active}")
    private String profile;


    @Override
    public List<VideoCassetteRecorder> findByArea(String areaId) {
        return videoCassetteRecorderRepository.findByAreaIdAndIsDeleted(areaId, false);
    }


    @Transactional
    @Override
    public VideoCassetteRecorder add(String areaId, String name, String serialNumber,Integer liveWay) {
        String accessToken = null; //ssoCallService.getAreaYinShiToken(areaId);
        boolean b = yinShiUtil.updateVCRName(accessToken, serialNumber, name);
        if(b){
            VideoCassetteRecorder vcr = new VideoCassetteRecorder();
            vcr.setName(name);
            vcr.setSerialNumber(serialNumber);
            vcr.setAreaId(areaId);
            vcr.setLiveWay(liveWay);
            vcr.setLiveWayVal(LiveRoomConstant.LiveWay.get(liveWay));
            videoCassetteRecorderRepository.save(vcr);
            return vcr;
        }else{
            throw new BusinessException(SIGN_ERROR,"新增失败！萤石云可能不存在此设备！");
        }
    }

    @Transactional
    @Override
    public boolean delete(String areaId, String vcrId) {
        VideoCassetteRecorder vcr = videoCassetteRecorderRepository.findByIdAndAreaId(vcrId, areaId);

        if(vcr == null){
            throw new BusinessException(ErrorCode.MATERIAL_NOT_EXIST, "录像机不存在");
        }

        videoCassetteRecorderRepository.delete(vcr);

        List<LiveRoom> liveRooms = liveRoomRepository.findAllByDeviceSerialAndAreaIdOrderByChannelNo(vcr.getSerialNumber(), areaId);

        liveRoomRepository.deleteAll(liveRooms);

        return true;
    }

    @Transactional
    @Override
    public VideoCassetteRecorder modify(String id, String name, String serialNumber,Integer liveWay, String areaId) {
        VideoCassetteRecorder vcr = videoCassetteRecorderRepository.findByIdAndAreaId(id, areaId);

        if(vcr == null){
            throw new BusinessException(ErrorCode.MATERIAL_NOT_EXIST, "录像机不存在");
        }

        String accessToken = null; // ssoCallService.getAreaYinShiToken(vcr.getAreaId());

        boolean b = yinShiUtil.updateVCRName(accessToken, serialNumber, name);
        if (b) {
            vcr.setName(name);
            vcr.setSerialNumber(serialNumber);
            vcr.setLiveWay(liveWay);
            vcr.setLiveWayVal(LiveRoomConstant.LiveWay.get(liveWay));
            videoCassetteRecorderRepository.saveAndFlush(vcr);
            //异步更新本录像机下所有摄像头的直播方式
            liveRoomRepository.updateLiveWay(serialNumber, liveWay,vcr.getAreaId(),LiveRoomConstant.LiveWay.get(liveWay));
            return vcr;
        }else{
            throw new BusinessException(SIGN_ERROR,"更新失败！萤石云可能不存在此设备！");
        }
    }

    @Transactional
    @Override
    public void refreshAll() {

        List<String> areaIds = videoCassetteRecorderRepository.findAllAreaIdNeedRefresh();
        for(String areaId : areaIds){
            List<VideoCassetteRecorder> oldList = videoCassetteRecorderRepository.findByAreaIdAndIsDeleted(areaId, false);

            String accessToken = null; //ssoCallService.getAreaYinShiToken(areaId);

            List<Map> list = yinShiUtil.getVCRList(accessToken);

            List<VideoCassetteRecorder> needSendMailList = Lists.newArrayList();
            for (Map map : list) {
                VideoCassetteRecorder recorder = match(oldList, map);
                if (Objects.nonNull(recorder)) {
                    if (recorder.getStatus() != Integer.valueOf(map.get("status").toString())) {
                        needSendMailList.add(recorder);
                    }
                    recorder.setStatus(Integer.valueOf(map.get("status").toString()));
                    recorder.setLastModified(new Date());
                    videoCassetteRecorderRepository.save(recorder);
                }
            }
            if (needSendMailList.size() > 0) {
                String content = "";
                for (VideoCassetteRecorder recorder : needSendMailList) {
                    AreaDTO area = null; //ssoCallService.getAreaById(recorder.getAreaId());
                    if (recorder.getStatus() == 1) {
                        content += String.format("[%s]园区录像机:[%s]，被老鼠找回来了\n", area.getName(), recorder.getName());
                    }
                    if (recorder.getStatus() == 0) {
                        content += String.format("[%s]园区录像机:[%s]，被猫吃掉了\n", area.getName(), recorder.getName());
                    }
                }
                if (profile.equals("pro"));
//                mailSenderHelper.sendSimpleMail(to, "录像机可能被猫吃掉了", content);
            }
        }
    }

    @Override
    @Transactional
    public Object refreshVCRSingle(String areaId, String deviceSerial) {

        if (StringUtils.isEmpty(deviceSerial)){
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "参数错误");
        }

        String accessToken = liveRoomService.getAreaYinShiToken(areaId);

        {
            //获取账号下所有录像机， 是否跟当前录像机符合, 并且刷新状态
            List<Map> list = yinShiUtil.getVCRList(accessToken);

            for (Map map : list) {
                String serial = map.get("deviceSerial").toString();
                if(StringUtils.isBlank(serial)){
                    continue;
                }

                VideoCassetteRecorder recorder = videoCassetteRecorderRepository.findByAreaIdAndAndSerialNumber(areaId, deviceSerial);

                recorder.setStatus(Integer.valueOf(map.get("status").toString()));
                recorder.setLastModified(new Date());
                videoCassetteRecorderRepository.save(recorder);
            }
        }

        //获取摄像头列表
        List<Map<String, Object>> list = yinShiUtil.getVCRListByVCRID(accessToken, deviceSerial);
//        List<Map<String, String>> maps = Lists.newArrayList();

        if(null == list){
            list = new ArrayList<>();
        }

        List<Map<String, String>> maps = list.stream().map( o ->
            ImmutableMap.of("deviceSerial", deviceSerial, "channelNo", o.get("channelNo").toString())
        ).collect(Collectors.toList());

        //获取播放地址
        List<Map<String, Object>> addressList = yinShiUtil.getAddressList(accessToken, maps);
        Map<String, Map<String, Object>> addressCache = new HashMap<>();
        addressList.forEach(k -> {
            addressCache.put(k.get("channelNo").toString(), k);
        });

        //找到对应的录像机
        VideoCassetteRecorder videoCassetteRecorder = videoCassetteRecorderRepository.findByAreaIdAndAndSerialNumber(areaId, deviceSerial);

        //删除
        List<LiveRoom> batch = new ArrayList<>();

        list.stream().forEach(l -> {
            //找到地址
            Map<String, Object> m = addressCache.get(l.get("channelNo"));
            if (m == null){
                return;
            }

            //找到已经存在的摄像头对象
            LiveRoom liveRoom = liveRoomRepository.findFirstByAreaIdAndDeviceSerialAndChannelNo(areaId, deviceSerial, Integer.parseInt(l.get("channelNo").toString()));
            if (liveRoom == null) {
                //没有则创建
                liveRoom = new LiveRoom();
                liveRoom.setChannelNo(Integer.parseInt(l.get("channelNo").toString()));
                liveRoom.setDeviceSerial(deviceSerial);
                liveRoom.setAreaId(areaId);
//                liveRoom.setIsPublic(false);

                if(!Objects.isNull(videoCassetteRecorder)){
                    liveRoom.setLiveWay(videoCassetteRecorder.getLiveWay());
                    liveRoom.setLiveWayVal(videoCassetteRecorder.getLiveWayVal());
                }
            }

            //填充播放地址
            liveRoom.setHls(m.get("hls") == null ? null : m.get("hls").toString());
            liveRoom.setHlsHd(m.get("hlsHd") == null ? null : m.get("hlsHd").toString());
            liveRoom.setUrl(m.get("rtmp") == null ? null : m.get("rtmp").toString());
            liveRoom.setHDUrl(m.get("rtmpHd") == null ? null : m.get("rtmpHd").toString());
            liveRoom.setStatus(m.get("status") == null ? null : Integer.valueOf(m.get("status").toString()));
            liveRoom.setStatusVal(ysCameraStatusVal(liveRoom.getStatus()));
            liveRoom.setException(Integer.parseInt(m.get("exception") == null ? null : m.get("exception").toString()));
            liveRoom.setName(m.get("deviceName") == null ? null : m.get("deviceName").toString());

            //
            batch.add(liveRoom);
        });

        if (batch.size() > 0) {
            liveRoomRepository.saveAll(batch);
        }

        return batch.size();
    }

    private String ysCameraStatusVal(int status){
        String statusVal = "";
        switch (status){
            case 0:
                statusVal = "未使用或直播已关闭";
                break;
            case 1:
                statusVal = LiveRoomConstant.Status.LIVING.valueOf();
                break;
            case 2:
                statusVal = LiveRoomConstant.Status.OVER.valueOf();
                break;
            case 3:
                statusVal = LiveRoomConstant.Status.STOP.valueOf();
                break;
            case -1:
                statusVal = LiveRoomConstant.Status.EXCEPTION.valueOf();
                break;
            default:
                statusVal = "未使用或直播已关闭";
                break;
        }
        return statusVal;
    }

    @Override
    public List<LiveRoom> getCameraByAreaIdAndSerial(String areaId,String deviceSerial) {
        List<LiveRoom> liveRooms = liveRoomRepository.findAllByDeviceSerialAndAreaIdOrderByChannelNo(deviceSerial,areaId);
        return liveRooms;
    }

    @Transactional
    @Override
    public Map openLive(String areaId, String deviceSerial, String channelNo) {
        String accessToken = null; //ssoCallService.getAreaYinShiToken(areaId);
        Map map = yinShiUtil.openLive(accessToken, deviceSerial, channelNo);
        if(map.get("ret").equals("200")){
            LiveRoom liveRoom = liveRoomRepository.findFirstByAreaIdAndDeviceSerialAndChannelNo(areaId, deviceSerial, Integer.parseInt(channelNo));
            liveRoom.setStatus(LiveRoomConstant.Status.LIVING.codeOf());
            liveRoom.setStatusVal(LiveRoomConstant.Status.LIVING.valueOf());
            Map<String,Object> deviceSerialMap = new HashMap<>();
            deviceSerialMap.put("deviceSerial",deviceSerial);
            deviceSerialMap.put("channelNo",channelNo);
            List list = Lists.newArrayList(deviceSerialMap);
            List addressList = yinShiUtil.getAddressList(accessToken, list);
            if(addressList.size()>0){
                Object o = addressList.get(0);
                if( o != null){
                    Map<String,Object> objectMap = (Map<String, Object>) o;
                    liveRoom.setHls(objectMap.get("hls") == null ? null : objectMap.get("hls").toString());
                    liveRoom.setHlsHd(objectMap.get("hlsHd") == null ? null : objectMap.get("hlsHd").toString());
                    liveRoom.setUrl(objectMap.get("rtmp") == null ? null : objectMap.get("rtmp").toString());
                    liveRoom.setHDUrl(objectMap.get("rtmpHd") == null ? null : objectMap.get("rtmpHd").toString());
                }
            }
            liveRoomRepository.save(liveRoom);
        }
        return map;
    }

    @Transactional
    @Override
    public Map closeLive(String areaId,String deviceSerial, String channelNo) {
        String accessToken = null; //ssoCallService.getAreaYinShiToken(areaId);
        Map map = yinShiUtil.closeLive(accessToken, deviceSerial, channelNo);
        if(map.get("ret").equals("200")){
            LiveRoom liveRoom = liveRoomRepository.findFirstByAreaIdAndDeviceSerialAndChannelNo(areaId, deviceSerial, Integer.parseInt(channelNo));
            liveRoom.setStatus(LiveRoomConstant.Status.STOP.codeOf());
            liveRoom.setStatusVal(LiveRoomConstant.Status.STOP.valueOf());
            liveRoomRepository.save(liveRoom);
        }
        return map;
    }

    @Transactional
    @Override
    public Object refreshAllArea() {
        List<VideoCassetteRecorder> all = videoCassetteRecorderRepository.findAll();
        AtomicBoolean state = new AtomicBoolean(false);
        for(VideoCassetteRecorder v : all){
            String areaId = v.getAreaId();
            String serialNumber = v.getSerialNumber();
            if(StringUtils.isNotBlank(areaId) && StringUtils.isNotBlank(serialNumber)){
                log.info("刷新录像机下摄像头：" + serialNumber);
                state = (AtomicBoolean) this.refreshVCRSingle(areaId, serialNumber);
            }
        }
        return state;
    }

    public VideoCassetteRecorder match(List<VideoCassetteRecorder> oldList, Map map) {
        Optional<VideoCassetteRecorder> optional = oldList.stream().filter(o -> o.getSerialNumber().equals(map.get("deviceSerial").toString())).findAny();
        return optional.isPresent() ? optional.get() : null;
    }

}
